﻿using System;
using System.Linq;
using System.Data.Linq.Mapping;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Data.Linq;

namespace Model
{
    [Table]
    public class Project:ModelBase,ILastUpdate
    {
        private Guid _id;

        public const int Finished = 8;
        public const int Running = 1;
        public const int Canceled = 0;

        [Column(IsPrimaryKey=true,CanBeNull=false,IsDbGenerated=false)]
        public Guid Id
        {
            get { return _id; }
            set
            {
                if (!Guid.Equals(value, _id))
                {
                    NotifyPropertyChanging("Id");
                    _id = value;
                    NotifyPropertyChanged("Id");
                }
            }
        }

        [Column]
        internal string _firstLocationId;

        private EntityRef<Location> _firstLocation;

        [Association(Storage = "_firstLocation", ThisKey = "_firstLocationId", OtherKey = "Id", IsForeignKey = true)]
        public Location FirstLocation
        {
            get { return _firstLocation.Entity; }
            set
            {
                NotifyPropertyChanging("FirstLocation");
                _firstLocation.Entity = value;
                if (value != null)
                {
                    _firstLocation.Entity.Id = Guid.NewGuid().ToString();
                    _firstLocationId = value.Id;
                }
                NotifyPropertyChanged("FirstLocation");
                Cal();
            }
        }

        [Column]
        internal string _targetId;

        private EntityRef<Location> _target;
        [Association(Storage = "_target",ThisKey="_targetId",OtherKey="Id",IsForeignKey=true)]
        public Location Target
        {
            get { return _target.Entity; }
            set
            {
                NotifyPropertyChanging("Target");
                _target.Entity = value;
                if (value != null)
                {
                    _target.Entity.Id = Guid.NewGuid().ToString();
                    _targetId = value.Id;
                }
                NotifyPropertyChanged("Target");
                Cal();
            }
        }

        private double _degree;
        [Column]
        public double Degree
        {
            get { return _degree; }
            set
            {
                if (value != _degree)
                {
                    NotifyPropertyChanging("Degree");

                    _degree = value;
                    NotifyPropertyChanged("Degree");
                }
                Cal();
            }
        }

        private int _status;
        [Column]
        public int Status
        {
            get { return _status; }
            set {
                NotifyPropertyChanging("Status");
                _status = value;
                NotifyPropertyChanged("Status");
            }
        }


        private DateTime _lastUpdate;

        [Column]
        public DateTime LastUpdate
        {
            get { return _lastUpdate; }
            set
            {
                if (value != _lastUpdate)
                {
                    NotifyPropertyChanging("LastUpdate");
                    _lastUpdate = value;
                    NotifyPropertyChanged("LastUpdate");
                }
            }
        }



        private double Distance()
        {
            if (FirstLocation == null || Target == null)
                return double.NaN;
            return Utils.Gps.Calculator.DistanceOfTwoPoints(FirstLocation.Longitude, FirstLocation.Latitude, Target.Longitude, Target.Latitude);
        }
        public double TargetHeight
        {
            get
            {
                var distance = Distance();
                var height = distance * Math.Tan(Degree);
                height = Math.Abs(height);
                return height;
            }
        }

        public string TargetHeightToShow
        {
            get
            {
                if (double.IsNaN(TargetHeight)) 
                    return "";
                return TargetHeight.ToString("0.00") + "m";
            }
        }

        public static Project New()
        {
            var project = new Project()
            {
                Id = Guid.NewGuid(),
                Status = Running
            };
            return project;
            
        }

        private void Cal()
        {
            if (FirstLocation != null && Target != null)
            {
                Status = Finished;
                this.Update();
                NotifyPropertyChanged("TargetHeight");
                NotifyPropertyChanged("TargetHeightToShow");
            }
        }

        public override string ToString()
        {
            return string.Format("{0}:{1}  --  {2}", LastUpdate.ToString("yyyy-MM-dd HH:mm"), Status == Running ? "Run" : Status == Finished ? "Finished" : "Error", TargetHeightToShow);
        }

    }
}
